﻿using System;
using System.Xml.Serialization;
using FortuneUniverse.Fortune.Algorithms;
using Newtonsoft.Json;

namespace FortuneUniverse.Fortune.Dyson
{
  public class PlanetData
  {
    public int seed;
    public int id;
    public int index;
    public int orbitAround;
    public int number;
    public int orbitIndex;
    public string name = string.Empty;
    public string overrideName = string.Empty;
    public float orbitRadius = 1f;
    public float orbitInclination;
    public float orbitLongitude;
    public double orbitalPeriod = 3600.0;
    public float orbitPhase;
    public float obliquity;
    public double rotationPeriod = 480.0;
    public float rotationPhase;
    public float radius = 200f;
    public float scale = 1f;
    public float sunDistance;
    public float habitableBias;
    public float temperatureBias;
    public float ionHeight;
    public float windStrength;
    public float luminosity;
    public float landPercent;
    public double mod_x;
    public double mod_y;
    public float waterHeight;
    public int waterItemId;
    public bool levelized;
    public EPlanetType type;
    public EPlanetSingularity singularity;
    public int theme;
    public int algoId;
    public PlanetData orbitAroundPlanet;
    [JsonIgnore]
    public VectorLF3 runtimePosition;
    [JsonIgnore]
    public VectorLF3 runtimePositionNext;
    [JsonIgnore]
    public Quaternion runtimeRotation;
    [JsonIgnore]
    public Quaternion runtimeRotationNext;
    [JsonIgnore]
    public Quaternion runtimeSystemRotation;
    [JsonIgnore]
    public Quaternion runtimeOrbitRotation;
    public float runtimeOrbitPhase;
    public float runtimeRotationPhase;
    [JsonIgnore]
    public VectorLF3 uPosition;
    [JsonIgnore]
    public VectorLF3 uPositionNext;
    [JsonIgnore]
    public Vector3 runtimeLocalSunDirection;
    public int[] veinSpotsSketch;
    public long[] veinAmounts;
    public PlanetData.VeinGroup[] veinGroups;
    public byte[] modData;
    public int precision = 160;
    public int segment = 5;
    [XmlIgnore]
    [JsonIgnore]
    public PlanetRawData data;
    public const int kMaxMeshCnt = 100;
    public float ambientSfxVolume;
    public bool landPercentDirty;
    public int factoryIndex = -1;
    public int[] gasItems;
    public float[] gasSpeeds;
    public float[] gasHeatValues;
    public double gasTotalHeat;
    [JsonIgnore]
    public Vector3 birthPoint;
    [JsonIgnore]
    public Vector3 birthResourcePoint0;
    [JsonIgnore]
    public Vector3 birthResourcePoint1;
    public bool loaded;
    public bool wanted;
    public bool loading;
    public bool factoryLoaded;
    public bool factoryLoading;
    public const float kEnterAltitude = 1000f;

    public PlanetData()
    {
      this.veinAmounts = new long[15];
      this.veinGroups = new PlanetData.VeinGroup[0];
    }

    public string displayName => string.IsNullOrEmpty(this.overrideName) ? this.name : this.overrideName;

    public float realRadius => this.radius * this.scale;

    public string typeString
    {
      get
      {
        string str = "未知".Translate();
        ThemeProto themeProto = LDB.themes.Select(this.theme);
        if (themeProto != null)
          str = themeProto.DisplayName;
        return str;
      }
    }

    public string singularityString
    {
      get
      {
        string empty = string.Empty;
        if (this.orbitAround > 0)
          empty += "卫星".Translate();
        if ((this.singularity & EPlanetSingularity.TidalLocked) != EPlanetSingularity.None)
          empty += "潮汐锁定永昼永夜".Translate();
        if ((this.singularity & EPlanetSingularity.TidalLocked2) != EPlanetSingularity.None)
          empty += "潮汐锁定1:2".Translate();
        if ((this.singularity & EPlanetSingularity.TidalLocked4) != EPlanetSingularity.None)
          empty += "潮汐锁定1:4".Translate();
        if ((this.singularity & EPlanetSingularity.LaySide) != EPlanetSingularity.None)
          empty += "横躺自转".Translate();
        if ((this.singularity & EPlanetSingularity.ClockwiseRotate) != EPlanetSingularity.None)
          empty += "反向自转".Translate();
        if ((this.singularity & EPlanetSingularity.MultipleSatellites) != EPlanetSingularity.None)
          empty += "多卫星".Translate();
        return empty;
      }
    }

    public void GenBirthPoints(PlanetRawData rawData, StarData star, int _birthSeed)
    {
      URandom1 urandom1 = new URandom1(_birthSeed);
      Pose pose = this.PredictPose(85.0);
      Vector3 vector3_1 = (Vector3) Maths.QInvRotateLF(pose.rotation, star.uPosition - (VectorLF3) pose.position * 40000.0);
      vector3_1.Normalize();
      Vector3 normalized1 = Vector3.Cross(vector3_1, Vector3.up).normalized;
      Vector3 normalized2 = Vector3.Cross(normalized1, vector3_1).normalized;
      int num1 = 0;
      while (num1 < 256)
      {
        float num2 = (float) (urandom1.NextDouble() * 2.0 - 1.0) * 0.5f;
        float num3 = (float) (urandom1.NextDouble() * 2.0 - 1.0) * 0.5f;
        Vector3 vector3_2 = vector3_1 + num2 * normalized1 + num3 * normalized2;
        vector3_2.Normalize();
        this.birthPoint = vector3_2 * (float) ((double) rawData.QueryHeight(vector3_2) + 0.200000002980232 + 1.60000002384186);
        normalized1 = Vector3.Cross(vector3_2, Vector3.up).normalized;
        normalized2 = Vector3.Cross(normalized1, vector3_2).normalized;
        bool flag = false;
        for (int index = 0; index < 10; ++index)
        {
          Vector2 vector2_1 = new Vector2((float) (urandom1.NextDouble() * 2.0 - 1.0), (float) (urandom1.NextDouble() * 2.0 - 1.0)).normalized * 0.1f;
          Vector2 vector2_2 = -vector2_1;
          float num4 = (float) (urandom1.NextDouble() * 2.0 - 1.0) * 0.06f;
          float num5 = (float) (urandom1.NextDouble() * 2.0 - 1.0) * 0.06f;
          vector2_2.x += num4;
          vector2_2.y += num5;
          Vector3 normalized3 = (vector3_2 + vector2_1.x * normalized1 + vector2_1.y * normalized2).normalized;
          Vector3 normalized4 = (vector3_2 + vector2_2.x * normalized1 + vector2_2.y * normalized2).normalized;
          this.birthResourcePoint0 = normalized3.normalized;
          this.birthResourcePoint1 = normalized4.normalized;
          float num6 = this.realRadius + 0.2f;
          if ((double) rawData.QueryHeight(vector3_2) > (double) num6 && (double) rawData.QueryHeight(normalized3) > (double) num6 && (double) rawData.QueryHeight(normalized4) > (double) num6)
          {
            Vector3 vpos1 = normalized3 + normalized1 * 0.03f;
            Vector3 vpos2 = normalized3 - normalized1 * 0.03f;
            Vector3 vpos3 = normalized3 + normalized2 * 0.03f;
            Vector3 vpos4 = normalized3 - normalized2 * 0.03f;
            Vector3 vpos5 = normalized4 + normalized1 * 0.03f;
            Vector3 vpos6 = normalized4 - normalized1 * 0.03f;
            Vector3 vpos7 = normalized4 + normalized2 * 0.03f;
            Vector3 vpos8 = normalized4 - normalized2 * 0.03f;
            if ((double) rawData.QueryHeight(vpos1) > (double) num6 && (double) rawData.QueryHeight(vpos2) > (double) num6 && (double) rawData.QueryHeight(vpos3) > (double) num6 && (double) rawData.QueryHeight(vpos4) > (double) num6 && (double) rawData.QueryHeight(vpos5) > (double) num6 && (double) rawData.QueryHeight(vpos6) > (double) num6 && (double) rawData.QueryHeight(vpos7) > (double) num6 && (double) rawData.QueryHeight(vpos8) > (double) num6)
            {
              flag = true;
              break;
            }
          }
        }
        if (flag)
          break;
      }
    }

    public Pose PredictPose(double time)
    {
      double num1 = time / this.orbitalPeriod + (double) this.orbitPhase / 360.0;
      int num2 = (int) (num1 + 0.1);
      double num3 = (num1 - (double) num2) * (2.0 * Math.PI);
      double num4 = time / this.rotationPeriod + (double) this.rotationPhase / 360.0;
      int num5 = (int) (num4 + 0.1);
      double num6 = (num4 - (double) num5) * 360.0;
      Vector3 position = Maths.QRotate(this.runtimeOrbitRotation, new Vector3((float) Math.Cos(num3) * this.orbitRadius, 0.0f, (float) Math.Sin(num3) * this.orbitRadius));
      if (this.orbitAroundPlanet != null)
      {
        Pose pose = this.orbitAroundPlanet.PredictPose(time);
        position.x += pose.position.x;
        position.y += pose.position.y;
        position.z += pose.position.z;
      }
      return new Pose(position, this.runtimeSystemRotation * Quaternion.AngleAxis((float) num6, Vector3.down));
    }

    public struct VeinGroup
    {
      public EVeinType type;
      public Vector3 pos;
      public int count;
      public long amount;
    }
  }
}
